<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: paolotiu</title>
    <description>The latest articles on DEV Community by paolotiu (@tiu).</description>
    <link>https://dev.to/tiu</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%2F597402%2Fff1d2e57-353b-4aba-a1c0-372761b83372.jpeg</url>
      <title>DEV Community: paolotiu</title>
      <link>https://dev.to/tiu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tiu"/>
    <language>en</language>
    <item>
      <title>Make users feel special by giving them their own subdomains.</title>
      <dc:creator>paolotiu</dc:creator>
      <pubDate>Mon, 23 Aug 2021 14:49:02 +0000</pubDate>
      <link>https://dev.to/tiu/make-users-feel-special-by-giving-them-their-own-subdomains-32ah</link>
      <guid>https://dev.to/tiu/make-users-feel-special-by-giving-them-their-own-subdomains-32ah</guid>
      <description>&lt;p&gt;Have you ever wondered how to enable users to create their own subdomain? For example &lt;em&gt;slack workspaces&lt;/em&gt; (space.slack.com) or &lt;em&gt;hashnode blogs&lt;/em&gt; (name.hashnode.dev).&lt;br&gt;
Well, Vercel makes it very easy since they have support for wildcard domains.&lt;/p&gt;
&lt;h2&gt;
  
  
  What are Wildcard Domains?
&lt;/h2&gt;

&lt;p&gt;You can think of a wildcard domain as a catch-all for subdomains.&lt;br&gt;
If I go to &lt;strong&gt;foo.domain.com&lt;/strong&gt; it will go to the same page as &lt;strong&gt;bar.domain.com&lt;/strong&gt;.&lt;br&gt;
Then on the client side, you can serve different content for different subdomains. This will make more sense later.&lt;/p&gt;

&lt;p&gt;Setting one up on Vercel is super easy and it has built-in HTTPS.&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding Wildcard Domains
&lt;/h2&gt;

&lt;p&gt;First, you need to have a domain available. You can buy one from any domain registrar like &lt;a href="https://namecheap.com"&gt;namecheap&lt;/a&gt; or &lt;a href="https://porkbun.com"&gt;porkbun&lt;/a&gt;.&lt;br&gt;
For this example, I'll use shopeetracker.com. It's a throwaway domain that I don't use anymore.&lt;/p&gt;

&lt;p&gt;Next, go to your projects &lt;strong&gt;Domains&lt;/strong&gt; tab, enter a wildcard domain, and follow the instructions stated. For example, my domain is shopeetracker.com and I got it from Namecheap.&lt;br&gt;
Then I'll input &lt;code&gt;*.shopeetracker.com&lt;/code&gt; and configure my nameservers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vvMFhiBk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1629729888686/fEVzNPemw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vvMFhiBk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1629729888686/fEVzNPemw.png" alt="nameserver.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have done that you're all set! Pretty easy right?&lt;/p&gt;
&lt;h2&gt;
  
  
  Detecting the subdomain
&lt;/h2&gt;

&lt;p&gt;Detecting the subdomain happens at the client-side since we don't have access to the window object on the server-side.&lt;br&gt;
Using a simple helper function we can extract the subdomain from the URL.&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getPageData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&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;splitHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isDev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;splitHost&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isDev&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;splitHost&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This is your the subdomain&lt;/span&gt;
    &lt;span class="c1"&gt;// Ex. if foo.domain.com then page === 'foo'&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;splitHost&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;www&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="k"&gt;return&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="c1"&gt;// You can do your fetching logic here for each subdomain&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;page&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="kc"&gt;null&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;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;A running example can be found on &lt;a href="https://shopeetracker.com"&gt;https://shopeetracker.com&lt;/a&gt;, and the source code is available in a &lt;a href="https://github.com/paolotiu/wildcard-domains-example"&gt;Github Repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Providing custom subdomains can make users feel special. And with wildcard domains, it can be done quickly.&lt;br&gt;
If you tried this out in any of your projects hit me up on &lt;a href="https://twitter.com/PaoloTiu_"&gt;Twitter&lt;/a&gt;.&lt;br&gt;
I also have a &lt;a href="https://buttondown.email/paolotiu"&gt;newsletter&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/paolotiu/wildcard-domains-example"&gt;Github Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://shopeetracker.com"&gt;Live Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vercel.com/blog/wildcard-domains"&gt;Vercel's Blog Post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>showdev</category>
      <category>tutorial</category>
      <category>react</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>How to get secure cookies working with Nginx</title>
      <dc:creator>paolotiu</dc:creator>
      <pubDate>Mon, 09 Aug 2021 08:25:35 +0000</pubDate>
      <link>https://dev.to/tiu/how-to-get-secure-cookies-working-with-nginx-4han</link>
      <guid>https://dev.to/tiu/how-to-get-secure-cookies-working-with-nginx-4han</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;As I was setting up my Node server in a VPS, I got confused as to why my cookies weren't being set.&lt;br&gt;
After some time I figured out that it works in the &lt;code&gt;development&lt;/code&gt; environment, but not in the &lt;code&gt;production&lt;/code&gt; environment.&lt;br&gt;
I kept prodding around to find out that when I set the &lt;code&gt;secure&lt;/code&gt; option to true the cookies weren't being sent.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: I'm using express-sessions my code roughly looks like this.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SESSION_SECRET&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;resave&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;saveUninitialized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="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;sid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;RedisStore&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;redisClient&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;httpOnly&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="na"&gt;secure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;365&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 1 year&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;After hours of fiddling, researching, failing, and &lt;em&gt;crying&lt;/em&gt;, I &lt;strong&gt;finally&lt;/strong&gt; found the solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;Apparently, you need to add the directive &lt;code&gt;proxy_set_header X-Forwarded-Proto https;&lt;/code&gt; to your nginx file.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt; &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$http_host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-NginX-Proxy&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:4000/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span class="s"&gt;https&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;And that's it! So much confusion just for one line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I mainly wrote this article out of frustration with the hours spent, hoping someone else won't go through that.&lt;/p&gt;

&lt;p&gt;As always you can follow me on &lt;a href="https://twitter.com/PaoloTiu_"&gt;Twitter&lt;/a&gt;, and I have a &lt;a href="https://buttondown.email/paolotiu"&gt;newsletter&lt;/a&gt; if you're into that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/expressjs/session/issues/281#issuecomment-191359194"&gt;Related Github Issue&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>nginx</category>
      <category>node</category>
    </item>
    <item>
      <title>👻 Jotai - State Simply Managed</title>
      <dc:creator>paolotiu</dc:creator>
      <pubDate>Tue, 03 Aug 2021 04:38:58 +0000</pubDate>
      <link>https://dev.to/tiu/jotai-state-simply-managed-3p2h</link>
      <guid>https://dev.to/tiu/jotai-state-simply-managed-3p2h</guid>
      <description>&lt;p&gt;As I refine my stack more and more, one of the values I look for is &lt;strong&gt;simplicity&lt;/strong&gt;.&lt;br&gt;
Simplicity allows me to move quick and iterate much faster. Jotai provides that for me.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Jotai?
&lt;/h2&gt;

&lt;p&gt;With so many state management libraries out there, why should Jotai even be considered?&lt;/p&gt;
&lt;h3&gt;
  
  
  Structure
&lt;/h3&gt;

&lt;p&gt;Jotai structures state in a &lt;strong&gt;bottom-up&lt;/strong&gt; approach which consists of atoms.&lt;br&gt;
This is contrary to the way redux/zustand structures their state (a &lt;strong&gt;top-down&lt;/strong&gt; approach).&lt;br&gt;
Your preference may vary, but the way Jotai does it is more straightforward to me.&lt;/p&gt;

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

&lt;p&gt;Using Jotai for the first time is quick --- &lt;strong&gt;&lt;em&gt;very quick&lt;/em&gt;&lt;/strong&gt;. Actually, let me show you.&lt;/p&gt;
&lt;h4&gt;
  
  
  First create a primitive atom
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { atom } from 'jotai';

const countAtom = atom(0);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Then use that atom anywhere in your component
&lt;/h4&gt;

&lt;p&gt;It works as you would expect &lt;code&gt;useState&lt;/code&gt; to work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { countAtom } from '../jotai.ts'

function Counter() {
  const [count, setCount] = useAtom(countAtom)
  return (
    &amp;lt;h1&amp;gt;
      {count}
      &amp;lt;button onClick={() =&amp;gt; setCount(c =&amp;gt; c + 1)}&amp;gt;one up&amp;lt;/button&amp;gt;
      // ...rest of code here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;Jotai was born to solve the extra re-render issue in React.&lt;br&gt;
Though most of the time this won't be an issue when using any popular state management libraries, it's still good.&lt;/p&gt;
&lt;h4&gt;
  
  
  Benchmarks
&lt;/h4&gt;

&lt;p&gt;This benchmark ran my machine with Ryzen 5 2600, Windows 11 Insiders Preview inside WSL2.&lt;br&gt;
The write scores are low compared to the original benchmarks.&lt;br&gt;
Most likely it's either because I'm running it inside WSL2, or its a machine difference.&lt;br&gt;
To see the benchmarks ran on another machine go to this &lt;a href="https://github.com/pmndrs/jotai/pull/486#issuecomment-845611351" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;type&lt;/th&gt;
&lt;th&gt;atoms&lt;/th&gt;
&lt;th&gt;ops/s&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;read&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;6 519 582&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;read&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;6 524 333&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;read&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td&gt;6 594 886&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;write&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;394 417&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;write&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;400 393&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;write&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td&gt;414 026&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Extra
&lt;/h3&gt;

&lt;p&gt;There are a few more things as to why you should consider Jotai.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Typescript oriented&lt;/li&gt;
&lt;li&gt;No string keys needed&lt;/li&gt;
&lt;li&gt;Lightweight (2.4kB minfied + gzipped)&lt;/li&gt;
&lt;li&gt;The mascot (it's cute c'mon)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Atoms
&lt;/h3&gt;

&lt;p&gt;Atoms are at the core of Jotai, the building blocks to create your state.&lt;br&gt;
I think the &lt;a href="https://docs.pmnd.rs/jotai/basics/primitives" rel="noopener noreferrer"&gt;docs&lt;/a&gt; says it best.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;State in Jotai is a set of atoms. An atom is a piece of state. Unlike useState in React, atoms are not tied to specific components.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Primitive atoms
&lt;/h3&gt;

&lt;p&gt;These atoms are as simple as it gets. Just pass an initial value.&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;atom&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;jotai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;countAtom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;atom&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Derived atoms
&lt;/h3&gt;

&lt;p&gt;Derived atoms are atoms that depend on other atoms.&lt;br&gt;
Whenever the atoms they depend on changes the value of these atoms also update.&lt;/p&gt;

&lt;p&gt;There are three types of derived atoms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read-only atom&lt;/li&gt;
&lt;li&gt;Write-only atom&lt;/li&gt;
&lt;li&gt;Read-Write atom&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create a derived atom we must pass a read function and an optional write function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;readOnlyAtom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;atom&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kd"&gt;get&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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;countAtom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;writeOnlyAtom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;atom&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="c1"&gt;// it's a convention to pass `null` for the first argument&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;update&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;// `update` is any single value we receive for updating this atom&lt;/span&gt;
    &lt;span class="c1"&gt;// It can be an object, string, int, etc.&lt;/span&gt;
    &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;countAtom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;countAtom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;readWriteAtom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;get&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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;countAtom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;countAtom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// you can set as many atoms as you want at the same time&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;get&lt;/code&gt; is used to read other atom values. It reacts to changes of its dependencies.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;set&lt;/code&gt; is used to write to write an atom value.&lt;br&gt;
It will invoke the write function of the target atom.&lt;/p&gt;
&lt;h3&gt;
  
  
  Note
&lt;/h3&gt;

&lt;p&gt;The value returned by the &lt;code&gt;atom&lt;/code&gt; function doesn't hold any state.&lt;br&gt;
It creates an atom config. We call these atoms, but it's important to know that these &lt;strong&gt;do not&lt;/strong&gt; hold any state.&lt;br&gt;
We'll see why in our next point.&lt;/p&gt;
&lt;h3&gt;
  
  
  Provider
&lt;/h3&gt;

&lt;p&gt;Provider is used to provide state for a component subtree.&lt;br&gt;
This means that we can use atoms in different locations, and they can have different values.&lt;br&gt;
Providers can be used for multiple subtrees, even nested. It works just like the React Context would.&lt;/p&gt;

&lt;p&gt;A Provider is not needed though, without it the atom will use default state it was defined with.&lt;/p&gt;

&lt;p&gt;Here's an example for different Provider situations:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/multiple-providers-xp5j7?fontsize=14&amp;amp;hidenavigation=1&amp;amp;theme=dark" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcodesandbox.io%2Fstatic%2Fimg%2Fplay-codesandbox.svg" alt="Edit Multiple Providers"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Other Goodies
&lt;/h2&gt;
&lt;h3&gt;
  
  
  atomWithStorage
&lt;/h3&gt;

&lt;p&gt;Jotai's minimalistic core API allows various utils to be built based on it.&lt;br&gt;
My favorite is &lt;a href="https://docs.pmnd.rs/jotai/api/utils#atom-with-storage" rel="noopener noreferrer"&gt;atomWithStorage&lt;/a&gt;.&lt;br&gt;
It allows you to persist values in &lt;code&gt;localStorage&lt;/code&gt;, &lt;code&gt;sessionStorage&lt;/code&gt;, or for React Native &lt;code&gt;AsyncStorage&lt;/code&gt;.&lt;br&gt;
I find it to be perfect for theming.&lt;/p&gt;

&lt;p&gt;The first parameter is the key within your chosen storage.&lt;/p&gt;

&lt;p&gt;The second parameter is the initial value&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;useAtom&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;jotai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;atomWithStorage&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;jotai/utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;themeAtom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;atomWithStorage&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;dark&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;light&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;theme&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;light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&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;setTheme&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useAtom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;themeAtom&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Welcome&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;theme&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
        &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
          &lt;span class="nf"&gt;setDarkMode&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&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="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="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="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;toggle&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Integrations
&lt;/h3&gt;

&lt;p&gt;Jotai can integrate with other popular libraries.&lt;br&gt;
Here are some notable ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.pmnd.rs/jotai/integrations/query" rel="noopener noreferrer"&gt;React Query&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.pmnd.rs/jotai/integrations/urql" rel="noopener noreferrer"&gt;URQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.pmnd.rs/jotai/integrations/zustand" rel="noopener noreferrer"&gt;Zustand&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.pmnd.rs/jotai/integrations/redux" rel="noopener noreferrer"&gt;Redux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.pmnd.rs/jotai/integrations/xstate" rel="noopener noreferrer"&gt;XState&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Getting Async
&lt;/h3&gt;

&lt;p&gt;Jotai has first-class support for async. It fully leverages React Suspense.&lt;br&gt;
They have &lt;a href="https://docs.pmnd.rs/jotai/basics/async" rel="noopener noreferrer"&gt;fantastic docs&lt;/a&gt;. Check it out!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Jotai is my choice for global state management. Pair it with react-query, and boom!&lt;br&gt;
You have straightforward state management all throughout. Don't be fooled though, simple does not mean powerful.&lt;/p&gt;

&lt;p&gt;How about you? What's your state management solution?&lt;br&gt;
You can &lt;a href="//mailto:me@paolotiu.com"&gt;contact me&lt;/a&gt; any time if you have questions or just wanna chat!&lt;/p&gt;

&lt;p&gt;For more tips and tricks you can &lt;a href="https://twitter.com/PaoloTiu_" rel="noopener noreferrer"&gt;follow me on twitter&lt;/a&gt;. I also have a &lt;a href="https://buttondown.email/paolotiu" rel="noopener noreferrer"&gt;newsletter&lt;/a&gt; if you're into that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.pmnd.rs/jotai/introduction" rel="noopener noreferrer"&gt;Jotai Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/dai_shi" rel="noopener noreferrer"&gt;Daishi Kato - Author of Jotai&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to get Tailwind Intellisense anywhere</title>
      <dc:creator>paolotiu</dc:creator>
      <pubDate>Sat, 31 Jul 2021 15:28:28 +0000</pubDate>
      <link>https://dev.to/tiu/how-to-get-tailwind-intellisense-anywhere-53ej</link>
      <guid>https://dev.to/tiu/how-to-get-tailwind-intellisense-anywhere-53ej</guid>
      <description>&lt;p&gt;As I was evaluating tailwind I there was one thing that pushed me over the edge -- &lt;strong&gt;intellisense&lt;/strong&gt;.&lt;br&gt;
The speed that I can go writing styles for my components, it was bliss. Though once I used other libraries like&lt;br&gt;
&lt;a href="https://github.com/lukeed/clsx" rel="noopener noreferrer"&gt;clsx&lt;/a&gt; or &lt;a href="https://headlessui.dev/" rel="noopener noreferrer"&gt;HeadlessUI&lt;/a&gt; I kinda got annoyed by the lack of intellisense. It wasn't &lt;em&gt;that&lt;/em&gt; bad, but enough to bug me.&lt;/p&gt;

&lt;p&gt;For example HeadlessUI's Transition component:&lt;/p&gt;

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

&lt;p&gt;Or the clsx library:&lt;/p&gt;

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

&lt;p&gt;so the question is:&lt;/p&gt;
&lt;h2&gt;
  
  
  How to get intellisense?
&lt;/h2&gt;

&lt;p&gt;Luckily after some searching I found out how.&lt;/p&gt;

&lt;p&gt;First go open your workspace settings.&lt;/p&gt;

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

&lt;p&gt;This will create a &lt;code&gt;settings.json&lt;/code&gt; file under a &lt;code&gt;.vscode&lt;/code&gt; folder if you don't already have one. You can define rules within it. The one we're interested about is &lt;code&gt;tailwindCSS.experimental.classRegex&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this we define an array of arrays containing regex to match a pattern.&lt;/p&gt;

&lt;p&gt;For example using the clsx library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tailwindCSS.experimental.classRegex"&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="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"clsx&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;(([^)]*)&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(?:'|&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;|`)([^']*)(?:'|&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;|`)"&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's review what happened there.&lt;/p&gt;

&lt;p&gt;The first item in the array is an expression to the match &lt;strong&gt;container&lt;/strong&gt;, and the second expression is to match the &lt;strong&gt;class lists&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;NOTE: Both expressions must contain only one capture group.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;If you only have a single class list like the HeadlessUI example, you can specify a single regular expression.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tailwindCSS.experimental.classRegex"&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="s2"&gt;"(?:enter|leave)(?:From|To)?=&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;s*(?:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;|')([^(?:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use multiple expressions for different contexts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tailwindCSS.experimental.classRegex"&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="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"clsx&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;(([^)]*)&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(?:'|&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;|`)([^']*)(?:'|&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;|`)"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"(?:enter|leave)(?:From|To)?=&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;s*(?:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;|')([^(?:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;I know, &lt;strong&gt;regex is hard&lt;/strong&gt;, so heres a repo containing multiple use cases.&lt;br&gt;
&lt;a href="https://github.com/paolotiu/tailwind-regex-list" rel="noopener noreferrer"&gt;https://github.com/paolotiu/tailwind-regex-list&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I encourage you to contribute if there are any other use cases that haven't been listed.&lt;br&gt;
Thank you :)&lt;/p&gt;




&lt;h3&gt;
  
  
  Links:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/paolotiu/tailwind-regex-list" rel="noopener noreferrer"&gt;Regex List Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tailwindlabs/tailwindcss-intellisense/issues/129" rel="noopener noreferrer"&gt;Related Issue&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>tailwindcss</category>
      <category>vscode</category>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>Cross posting strategies </title>
      <dc:creator>paolotiu</dc:creator>
      <pubDate>Tue, 27 Jul 2021 02:57:43 +0000</pubDate>
      <link>https://dev.to/tiu/cross-posting-strategies-3jcl</link>
      <guid>https://dev.to/tiu/cross-posting-strategies-3jcl</guid>
      <description>&lt;p&gt;Hey! I recently got into blogging, mainly in hashnode. I wanted to cross post though throughout medium, DEV, personal website, etc.. I found it quite a pain to copy paste everywhere. I also have some questions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Do you use any tools? If yes, what is it? If no, why?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do you handle SEO. I assume you fill in the canonical url right?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do you measure analytics throughout all platforms?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thank you so much!&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>help</category>
    </item>
  </channel>
</rss>
