<?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: Nico Andrade</title>
    <description>The latest articles on DEV Community by Nico Andrade (@nicoandrade).</description>
    <link>https://dev.to/nicoandrade</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%2F813008%2F5c820b56-dd1d-4919-8de9-b1c26bf7ad78.jpg</url>
      <title>DEV Community: Nico Andrade</title>
      <link>https://dev.to/nicoandrade</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nicoandrade"/>
    <language>en</language>
    <item>
      <title>I made a realtime 1v1 game with Next.js &amp; Tailwind CSS, learn how</title>
      <dc:creator>Nico Andrade</dc:creator>
      <pubDate>Thu, 10 Feb 2022 22:13:53 +0000</pubDate>
      <link>https://dev.to/nicoandrade/i-made-a-realtime-1v1-game-with-nextjs-tailwind-css-learn-how-536b</link>
      <guid>https://dev.to/nicoandrade/i-made-a-realtime-1v1-game-with-nextjs-tailwind-css-learn-how-536b</guid>
      <description>&lt;p&gt;Everyone knows about Wordle the game where you have to guess a 5 letter word and you only have 6 attempts.&lt;/p&gt;

&lt;p&gt;So I thought that will be a good idea to make a version where you can play against another player to see who can guess the word first.&lt;br&gt;
And that you can see in realtime the guesses from your opponent.&lt;/p&gt;

&lt;p&gt;I called it &lt;a href="https://warwordly.com" rel="noopener noreferrer"&gt;WarWordly&lt;/a&gt; and it was product of the day in &lt;a href="https://www.producthunt.com/posts/warwordly" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Rules of the game
&lt;/h2&gt;

&lt;p&gt;The rules of the game are simple enough, you start with a valid word and each letter receives a color acording to this rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⬜️ Gray: the letter is incorrect&lt;/li&gt;
&lt;li&gt;🟧 Orange: the letter is correct but in the wrong position&lt;/li&gt;
&lt;li&gt;🟩 Green: the letter is correct and is in the correct position&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qdtghldd59ik6xuj3cf.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%2F3qdtghldd59ik6xuj3cf.png" alt="Guessing the word"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Make Wordle a 1v1 game
&lt;/h2&gt;

&lt;p&gt;The idea for this game is that we can compete with another player, and for that we have to see how our opponent is doing, like this:&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%2F7y4lkinmro6xvf1a5dh6.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%2F7y4lkinmro6xvf1a5dh6.png" alt="Playing against opponent"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So on the left is our guesses and on the right is our opponent.&lt;/p&gt;
&lt;h2&gt;
  
  
  Making it realtime
&lt;/h2&gt;

&lt;p&gt;The main technology used was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;▲ &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; as a React app&lt;/li&gt;
&lt;li&gt;🔋 &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt; for DB, Auth &amp;amp; Realtime&lt;/li&gt;
&lt;li&gt;🎨 &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt; for styling&lt;/li&gt;
&lt;li&gt;💾 &lt;a href="https://swr.vercel.app/" rel="noopener noreferrer"&gt;SWR&lt;/a&gt; for data fetching&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tools make it so easy right know to start with an idea and make it real so anyone can use it, and why not, make your little game Product of the Day on Product Hunt.&lt;/p&gt;

&lt;p&gt;The entire game is Open Source and you can see the &lt;a href="https://github.com/nicoandrade/warwordly" rel="noopener noreferrer"&gt;project on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We are going to focus on the realtime feature in this post.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's code
&lt;/h2&gt;

&lt;p&gt;On Supabase you can create any kind of PostgreSQL database, but they have a really cool feature where you can create subscription to any table with their &lt;a href="https://github.com/supabase/supabase-js" rel="noopener noreferrer"&gt;javascript client&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Just install their client on your project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @supabase/supabase-js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then import the client into your page&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&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;@supabase/supabase-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SUPABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SUPABASE_ANON_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can grab your &lt;code&gt;SUPABASE_URL&lt;/code&gt; and &lt;code&gt;SUPABASE_ANON_KEY&lt;/code&gt; from your Supabase account.&lt;/p&gt;

&lt;p&gt;Now we are going to create a &lt;a href="https://reactjs.org/docs/hooks-effect.html" rel="noopener noreferrer"&gt;React Hook&lt;/a&gt; to subscribe to our table from our database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;battleId&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="c1"&gt;// Subscribe to the Battle&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;battleSubscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`battles:id=eq.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;battleId&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="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UPDATE&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;payload&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;// Updates all the data from the Battle to SWR&lt;/span&gt;
            &lt;span class="nf"&gt;battleMutate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&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="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Cleanup on unmount&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;battleSubscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&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;battleId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is where the magic happens, so let's take a closer look 👇.&lt;/p&gt;

&lt;p&gt;First we import &lt;code&gt;useEffect&lt;/code&gt; from React.&lt;br&gt;
Then we create our hook, which is this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// code...&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;battleId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use &lt;code&gt;battleId&lt;/code&gt; as a dependency for the Hook, this is a variable with our Battle ID, since we need the ID to find the battle on our database.&lt;/p&gt;

&lt;p&gt;After that all we have to do is use the Supabase JS client to &lt;a href="https://supabase.com/docs/reference/javascript/subscribe" rel="noopener noreferrer"&gt;create a new subscription&lt;/a&gt; to our database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Subscribe to the Battle&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;battleSubscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`battles:id=eq.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;battleId&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="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UPDATE&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;payload&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;// Updates all the data from the Battle to SWR&lt;/span&gt;
        &lt;span class="nf"&gt;battleMutate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&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="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code sends us a JS object everytime someone makes an &lt;code&gt;UPDATE&lt;/code&gt; on our database.&lt;/p&gt;

&lt;p&gt;This is how we keep track of the guesses from our opponent.&lt;/p&gt;

&lt;p&gt;Then we can update the state of the battle using the awesome &lt;a href="https://swr.vercel.app/" rel="noopener noreferrer"&gt;SWR&lt;/a&gt; and its mutate function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Updates all the data from the Battle to SWR&lt;/span&gt;
&lt;span class="nf"&gt;battleMutate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&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.&lt;/p&gt;

&lt;p&gt;This is the code that lets the game be in realtime and see who player guess the word first.&lt;/p&gt;

&lt;p&gt;You can see this code on &lt;a href="https://github.com/nicoandrade/warwordly/blob/9688dd49cee19e92c52746aaf6034866e759ca19/pages/battles/%5BbattleId%5D/index.js#L242" rel="noopener noreferrer"&gt;the repo on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ending
&lt;/h2&gt;

&lt;p&gt;I hope that this short post helps you learn how to make an easy realtime feature on your app with just a few lines of code.&lt;/p&gt;

&lt;p&gt;🎮 You can &lt;a href="https://warwordly.com/" rel="noopener noreferrer"&gt;play the game here&lt;/a&gt;&lt;br&gt;
🛠 View the &lt;a href="https://github.com/nicoandrade/warwordly" rel="noopener noreferrer"&gt;entire project on GitHub&lt;/a&gt;&lt;br&gt;
🙋‍♂️ Say hi &lt;a href="https://twitter.com/NicoAndrade" rel="noopener noreferrer"&gt;on Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>nextjs</category>
      <category>tailwindcss</category>
    </item>
  </channel>
</rss>
